/* $Id: VBoxMPTypes.h $ */
/** @file
 * VBox WDDM Miniport driver
 */

/*
 * Copyright (C) 2011-2020 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef _WDDM_INCLUDE_WDDM_VBOXMPTYPES_H_
#define _WDDM_INCLUDE_WDDM_VBOXMPTYPES_H_

#include <ntdef.h>

#include "common/VBoxMPIf.h"
#include "VBoxVideo.h"
#include "CommonDef.h"

typedef struct VBOXWDDM_ALLOCATION *PVBOXWDDM_ALLOCATION;
typedef struct _VBOXMP_DEVEXT *PVBOXMP_DEVEXT;

/* A small buffer fills quickly by commands. A large buffer does not allow effective preemption.
 * 16K is an aritrary value, which allows to batch enough commands, but not too many.
 */
#define VBOXWDDM_C_DMA_BUFFER_SIZE         0x10000   //64KB
/* Private data is rather small, so one page is more than enough. */
#define VBOXWDDM_C_DMA_PRIVATEDATA_SIZE    0x10000   //64KB

#define VBOXWDDM_C_ALLOC_LIST_SIZE         0xc00
#define VBOXWDDM_C_PATH_LOCATION_LIST_SIZE 0xc00

#define VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS 0x01
#define VBOXWDDM_HGSYNC_F_SYNCED_LOCATION   0x02
#define VBOXWDDM_HGSYNC_F_SYNCED_VISIBILITY 0x04
#define VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY   0x08
#define VBOXWDDM_HGSYNC_F_SYNCED_ALL        (VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS | VBOXWDDM_HGSYNC_F_SYNCED_LOCATION | \
                                             VBOXWDDM_HGSYNC_F_SYNCED_VISIBILITY | VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY)
#define VBOXWDDM_HGSYNC_F_CHANGED_LOCATION_ONLY (VBOXWDDM_HGSYNC_F_SYNCED_ALL & ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION)
#define VBOXWDDM_HGSYNC_F_CHANGED_TOPOLOGY_ONLY (VBOXWDDM_HGSYNC_F_SYNCED_ALL & ~VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY)

#define VBOXWDDM_C_POINTER_MAX_WIDTH  128
#define VBOXWDDM_C_POINTER_MAX_HEIGHT 128
#define VBOXWDDM_C_POINTER_MAX_WIDTH_LEGACY  64
#define VBOXWDDM_C_POINTER_MAX_HEIGHT_LEGACY 64

#define VBOXWDDM_POINTER_ATTRIBUTES_SIZE VBOXWDDM_ROUNDBOUND( \
         VBOXWDDM_ROUNDBOUND( sizeof (VIDEO_POINTER_ATTRIBUTES), 4 ) + \
         VBOXWDDM_ROUNDBOUND(VBOXWDDM_C_POINTER_MAX_WIDTH * VBOXWDDM_C_POINTER_MAX_HEIGHT * 4, 4) + \
         VBOXWDDM_ROUNDBOUND((VBOXWDDM_C_POINTER_MAX_WIDTH * VBOXWDDM_C_POINTER_MAX_HEIGHT + 7) >> 3, 4) \
          , 8)

typedef struct _VBOXWDDM_POINTER_INFO
{
    UINT32 xPos;
    UINT32 yPos;
    union
    {
        VIDEO_POINTER_ATTRIBUTES data;
        char buffer[VBOXWDDM_POINTER_ATTRIBUTES_SIZE];
    } Attributes;
    volatile UINT64 lastNoVisibleTime;
    volatile UINT32 hasPendingNoVisible;
    volatile UINT64 lastSetShapeTime;
    volatile UINT32 hasPendingSetShape;
} VBOXWDDM_POINTER_INFO, * PVBOXWDDM_POINTER_INFO;

typedef struct _VBOXWDDM_GLOBAL_POINTER_INFO
{
    UINT32 iLastReportedScreen;
} VBOXWDDM_GLOBAL_POINTER_INFO, * PVBOXWDDM_GLOBAL_POINTER_INFO;

typedef struct VBOXWDDM_ADDR
{
    /* if SegmentId == NULL - the sysmem data is presented with pvMem */
    UINT SegmentId;
    union {
        VBOXVIDEOOFFSET offVram;
        void *pvMem;
    };
} VBOXWDDM_ADDR, *PVBOXWDDM_ADDR;

typedef struct VBOXWDDM_ALLOC_DATA
{
    VBOXWDDM_SURFACE_DESC SurfDesc;
    VBOXWDDM_ADDR Addr;
    UINT32 hostID;
    UINT32 cHostIDRefs;
} VBOXWDDM_ALLOC_DATA, *PVBOXWDDM_ALLOC_DATA;

typedef struct VBOXWDDM_ALLOCATION
{
    VBOXWDDM_ALLOC_TYPE enmType;
    D3DDDI_RESOURCEFLAGS fRcFlags;

    BOOLEAN fDeleted;
    BOOLEAN bVisible;
    BOOLEAN bAssigned;

    VBOXWDDM_ALLOC_DATA AllocData;
    struct VBOXWDDM_RESOURCE *pResource;
    /* to return to the Runtime on DxgkDdiCreateAllocation */
    DXGK_ALLOCATIONUSAGEHINT UsageHint;

    UINT32 iIndex;
    UINT32 cOpens;
    KSPIN_LOCK OpenLock;
    LIST_ENTRY OpenList;
    /* helps tracking when to release wine shared resource */
    UINT32 cShRcRefs;
    HANDLE hSharedHandle;
    INT CurVidPnSourceId;              /* Source index if used for a source, otherwise -1. */
#ifdef VBOX_WITH_VMSVGA3D_DX
    /* Direct3D driver data for .enmType == VBOXWDDM_ALLOC_TYPE_D3D. */
    struct
    {
        VBOXDXALLOCATIONDESC    desc;
        UINT32                  sid;                        /* For surfaces. */
        UINT32                  mobid;                      /* For surfaces and shaders. */
        UINT32                  SegmentId;                  /* Segment of the allocation. */
        union
        {
            PMDL                pMDL;                       /* Guest backing for aperture segment 2. */
            struct
            {
                struct VMSVGAMOB *pMob;                     /* Mob for the pages. */
            } gb;
        };
    } dx;
#endif /* VBOX_WITH_VMSVGA3D_DX */
} VBOXWDDM_ALLOCATION, *PVBOXWDDM_ALLOCATION;

typedef struct VBOXWDDM_SOURCE
{
    struct VBOXWDDM_ALLOCATION *pPrimaryAllocation;
    VBOXWDDM_ALLOC_DATA AllocData;
    UINT8 u8SyncState;
    BOOLEAN fTargetsReported;
    BOOLEAN bVisible;
    BOOLEAN bBlankedByPowerOff;

    KSPIN_LOCK AllocationLock;
    POINT VScreenPos;
    VBOXWDDM_POINTER_INFO PointerInfo;
    UINT32 cTargets;
    VBOXCMDVBVA_SCREENMAP_DECL(UINT32, aTargetMap);
} VBOXWDDM_SOURCE, *PVBOXWDDM_SOURCE;

typedef struct VBOXWDDM_TARGET
{
    RTRECTSIZE Size;
    UINT32 u32Id;
    D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
    /* since there coul be multiple state changes on auto-resize,
     * we pend notifying host to avoid flickering */
    UINT8 u8SyncState;
    BOOLEAN fConnected;
    BOOLEAN fConfigured;
    BOOLEAN fBlankedByPowerOff;

    /* Whether the host has disabled the virtual screen. */
    /** @todo This should be merged with fConnected. */
    BOOLEAN fDisabled;
} VBOXWDDM_TARGET, *PVBOXWDDM_TARGET;

typedef enum
{
    VBOXWDDM_DEVICE_TYPE_UNDEFINED = 0,
    VBOXWDDM_DEVICE_TYPE_SYSTEM
} VBOXWDDM_DEVICE_TYPE;

typedef struct VBOXWDDM_DEVICE
{
    PVBOXMP_DEVEXT pAdapter; /* Adapder info */
    HANDLE hDevice; /* handle passed to CreateDevice */
    VBOXWDDM_DEVICE_TYPE enmType; /* device creation flags passed to DxgkDdiCreateDevice, not sure we need it */
} VBOXWDDM_DEVICE, *PVBOXWDDM_DEVICE;

typedef struct VBOXWDDM_OPENALLOCATION
{
    LIST_ENTRY ListEntry;
    D3DKMT_HANDLE hAllocation;
    PVBOXWDDM_ALLOCATION pAllocation;
    PVBOXWDDM_DEVICE pDevice;
    UINT32 cShRcRefs;
    UINT32 cOpens;
    UINT32 cHostIDRefs;
} VBOXWDDM_OPENALLOCATION, *PVBOXWDDM_OPENALLOCATION;

typedef struct VBOXWDDM_RESOURCE
{
    VBOXWDDMDISP_RESOURCE_FLAGS fFlags;
    volatile UINT32 cRefs;
    VBOXWDDM_RC_DESC RcDesc;
    BOOLEAN fDeleted;
    UINT32 cAllocations;
    VBOXWDDM_ALLOCATION aAllocations[1];
} VBOXWDDM_RESOURCE, *PVBOXWDDM_RESOURCE;

struct VMSVGACONTEXT;

typedef struct VBOXWDDM_CONTEXT
{
    struct VBOXWDDM_DEVICE *pDevice;
    HANDLE hContext;
    VBOXWDDM_CONTEXT_TYPE enmType;
    UINT  NodeOrdinal;
    UINT  EngineAffinity;
    BOOLEAN fRenderFromShadowDisabled;

    struct VMSVGACONTEXT *pSvgaContext;
} VBOXWDDM_CONTEXT, *PVBOXWDDM_CONTEXT;

DECLINLINE(char const *) vboxWddmAllocTypeString(PVBOXWDDM_ALLOCATION pAlloc)
{
    switch (pAlloc->enmType) {
        case VBOXWDDM_ALLOC_TYPE_UNEFINED:                 return "UNEFINED";
        case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE: return "SHAREDPRIMARYSURFACE";
        case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:        return "SHADOWSURFACE";
        case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE:       return "STAGINGSURFACE";
        case VBOXWDDM_ALLOC_TYPE_STD_GDISURFACE:           return "GDISURFACE";
        case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:           return "UMD_RC_GENERIC";
        case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER:         return "UMD_HGSMI_BUFFER";
        default: break;
    }
    return "UNKNOWN";
}

#endif
